/**    
 * 文件名：AbractApprovalHandler.java</br>
 *    
 * 版本信息：v1.0</br>
 * 日期：2017年10月13日</br>
 * © 2005-2017 雷技信息科技（上海）有限公司版权所有</br>
 *
 */
package com.logic.landseaserver.models.approval.taskhandle;

import java.util.Date;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.logic.common.security.SecurityUtils;
import com.logic.landseaserver.common.LandeaConstants.ApprovalStatus;
import com.logic.landseaserver.common.exception.LandseaException;
import com.logic.landseaserver.common.exception.ResultCodes.ApprovalResultCode;
import com.logic.landseaserver.domain.ApprovalLogRecord;
import com.logic.landseaserver.domain.ApprovalRecord;
import com.logic.landseaserver.domain.ApprovalTempRecord;
import com.logic.landseaserver.models.approval.bean.ApprovalCheckResult;
import com.logic.landseaserver.models.approval.bean.ApprovalReq;
import com.logic.landseaserver.models.approval.bean.SubmitApprovalReq;
import com.logic.system.ws.dto.UserRoleDTO;

/**
 *
 * 项目名称：system-server</br>
 * 类名称：AbractApprovalHandler</br>
 * 类描述：</br>
 * 创建人：Aaron</br>
 * 创建时间：2017年10月13日 下午3:52:53</br>
 * 
 * @version 1.0
 *
 */
public abstract class AbractApprovalHandler
{
    public static final String BEANID = "_ApprovalHandler";
    
    private static final Logger LOGGER = LoggerFactory.getLogger(AbractApprovalHandler.class);
    
    /**
     * 
     * [简要描述]：提交审批的检查</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-10-16)</br>
     *
     * @param submitApprovalReq
     * @return
     * @throws LandseaException
     *
     */
    public ApprovalCheckResult submitCheck(SubmitApprovalReq submitApprovalReq)
        throws LandseaException
    {
        try
        {
            ApprovalCheckResult checkResult = new ApprovalCheckResult();
            
            // 自定义检查
            submitCheckCustom(submitApprovalReq, checkResult);
            
            // 以下是公共校验
            ApprovalHelper approvalHelper = ApprovalHelper.getInstance();
            
            // 检查审批流程模板是否存在
            List<ApprovalTempRecord> tempList =
                approvalHelper.getApprovalTempRecordReadMapper().selectByFlowTempId(submitApprovalReq.getFlowTempId());
            
            if (CollectionUtils.isEmpty(tempList))
            {
                throw LandseaException.createException(ApprovalResultCode.E00640003);
            }
            checkResult.setFlowTempList(tempList);
            
            // 检查审核是否存在
            ApprovalRecord queryCondition = new ApprovalRecord();
            queryCondition.setTaskId(submitApprovalReq.getTaskId());
            queryCondition.setTaskType(submitApprovalReq.getTaskType());
            ApprovalRecord approvalRecord = approvalHelper.getApprovalRecordReadMapper().selectByTask(queryCondition);
            // 不存在审批、或者状态为拒绝，都可以提交审批
            if (null != approvalRecord && !approvalRecord.getDeleted() 
                && !ApprovalStatus.AREFUSED.equals(approvalRecord.getApproveStatus()))
            {
                throw LandseaException.createException(ApprovalResultCode.E00650003);
            }
            
            checkResult.setCurrentApprovalRecord(approvalRecord);
            
            return checkResult;
        }
        catch (LandseaException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            LOGGER.error("Approval submitCheck error.", e);
            throw LandseaException.createException(ApprovalResultCode.E00650002, e);
        }
    }
    
    /**
     * 
     * [简要描述]：</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-10-16)</br>
     *
     * @param approvalReq
     * @return
     * @throws LandseaException
     *
     */
    public ApprovalCheckResult approval(ApprovalReq approvalReq)
        throws LandseaException
    {
        try
        {
            ApprovalCheckResult checkResult = new ApprovalCheckResult();
            
            // 以下是公共校验
            ApprovalHelper approvalHelper = ApprovalHelper.getInstance();
            // 检查
            Integer taskId = approvalReq.getTaskId();
            String taskType = approvalReq.getTaskType();
            
            // 审核动作只能是通过、拒绝
            if (!(ApprovalStatus.APASS.equals(approvalReq.getApprovalStatus())
                || ApprovalStatus.AREFUSED.equals(approvalReq.getApprovalStatus())))
            {
                throw LandseaException.createException(ApprovalResultCode.E00640004);
            }
            
            // 获取审核
            ApprovalRecord queryCondition = new ApprovalRecord();
            queryCondition.setTaskId(taskId);
            queryCondition.setTaskType(taskType);
            ApprovalRecord approvalRecord = approvalHelper.getApprovalRecordReadMapper().selectByTask(queryCondition);
            if (null == approvalRecord || approvalRecord.getDeleted())
            {
                throw LandseaException.createException(ApprovalResultCode.E00650005);
            }
            
            checkResult.setCurrentApprovalRecord(approvalRecord);
            
            // 校验状态
            String approvalStatus = approvalRecord.getApproveStatus();
            if (ApprovalStatus.APASS.equals(approvalStatus))
            {
                // 审核已完成
                throw LandseaException.createException(ApprovalResultCode.E00650006);
            }
            
            // 自定义检查
            approvalCheckCustom(approvalReq, checkResult);
            
            // 检查审批流程模板是否存在
            // 流程步骤从小到大排列
            List<ApprovalTempRecord> tempList =
                approvalHelper.getApprovalTempRecordReadMapper().selectByFlowTempId(approvalRecord.getFlowTempId());
            
            if (CollectionUtils.isEmpty(tempList))
            {
                throw LandseaException.createException(ApprovalResultCode.E00640003);
            }
            checkResult.setFlowTempList(tempList);
            
            int tempCount = tempList.size();
            
            // 当前的审核节点
            int currentNodeId = approvalRecord.getNodeId();
            // 下一个审核节点
            int nextNodeId = currentNodeId;
            ApprovalTempRecord currentApproval = null;
            String currentApprovalRole = null;
            
            int currentIndex = -1;
            for (int i = 0; i < tempCount; i++)
            {
                currentApproval = tempList.get(i);
                
                if (currentNodeId == currentApproval.getNodeId())
                {
                    // 记录当前的索引号，用来判断是否为最后一个审核节点
                    currentIndex = i;
                    currentApprovalRole = currentApproval.getApproveRoleCode();
                    // 检查是否有审核权限
                    checkCurrentApprovalAuth(currentApprovalRole, approvalHelper);
                    break;
                }
            }
            
            // 获取下一步审核状态
            String approvalStatusNext = null;
            // 如果是拒绝操作
            if (ApprovalStatus.AREFUSED.equals(approvalReq.getApprovalStatus()))
            {
                approvalStatusNext = approvalReq.getApprovalStatus();
                nextNodeId = currentNodeId;
            }
            else
            {
                // 已是最后一个节点，下一步改成审核成功/拒绝
                if (currentIndex + 1 == tempCount)
                {
                    approvalStatusNext = approvalReq.getApprovalStatus();
                    nextNodeId = currentNodeId;
                }
                else
                {
                    // 否则获取下一个节点的
                    ApprovalTempRecord nextApprovalTempRecord = tempList.get(currentIndex + 1);
                    nextNodeId = nextApprovalTempRecord.getNodeId();
                    approvalStatusNext = nextApprovalTempRecord.getApproveStatus();
                    checkResult.setNextApprovalTempRecord(nextApprovalTempRecord);
                }
            }
            
            
            Date currentDate = new Date();
            Integer userId = SecurityUtils.getCurrentLogin().getUserId();
            // 获取审核用户的名称
            String username = approvalHelper.getApprovalRecordReadMapper().selectApprovalUserName(userId);
            
            // 开始审核，修改审核表，修改成下一个状态
            ApprovalRecord updateApprovalRecord = new ApprovalRecord();
            updateApprovalRecord.setId(approvalRecord.getId());
            updateApprovalRecord.setApproveStatus(approvalStatusNext);
            updateApprovalRecord.setNodeId(nextNodeId);
            updateApprovalRecord.setLastModifiedBy(userId);
            updateApprovalRecord.setLastModifiedDtm(currentDate);
            approvalHelper.getApprovalRecordWriteMapper().updateByPrimaryKeySelective(updateApprovalRecord);
            
            // 入库审核日志表,记录当前的审核
            ApprovalLogRecord insertLog = new ApprovalLogRecord();
            insertLog.initCommonField();
            insertLog.setApprovalId(approvalRecord.getId());
            // 通过/拒绝
            insertLog.setApprovalStatus(approvalReq.getApprovalStatus());
            insertLog.setApprovalTime(currentDate);
            insertLog.setComment(approvalReq.getComment());
            insertLog.setUserId(userId);
            insertLog.setUsername(username);
            insertLog.setApprovalRoleCode(currentApprovalRole);
            insertLog.setApprovalTime(currentDate);
            approvalHelper.getApprovalLogRecordWriteMapper().insertSelective(insertLog);
            
            // 更新审核对象，给自定义业务
            approvalRecord.setApproveStatus(approvalStatusNext);
            
            // 自定义业务操作 
            LOGGER.info("approval|开始自定义处理." + approvalRecord.toString());
            approvalCustom(approvalReq, checkResult);
            
            return checkResult;
        }
        catch (LandseaException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            LOGGER.error("Approval error.", e);
            throw LandseaException.createException(ApprovalResultCode.E00650009, e);
        }
    }
    
    /**
     * 
     * [简要描述]：各个task自己的校验</br>
     * [详细描述]：提交审核的校验</br>
     * [作者]：Aaron(2017-10-13)</br>
     *
     * @param submitApprovalReq
     *
     */
    protected abstract void submitCheckCustom(SubmitApprovalReq submitApprovalReq, ApprovalCheckResult checkResult)
        throws LandseaException;
    
    /**
     * 
     * [简要描述]：各个task自己的校验</br>
     * [详细描述]：审核校验</br>
     * [作者]：Aaron(2017-10-13)</br>
     *
     *
     */
    protected abstract void approvalCheckCustom(ApprovalReq approvalReq, ApprovalCheckResult checkResult)
        throws LandseaException;
    
    /**
     * 
     * [简要描述]：业务自定义处理</br>
     * [详细描述]：提交审核</br>
     * [作者]：Aaron(2017-10-13)</br>
     *
     * @param ApprovalRecord insertApproval
     * @param checkResult
     * @throws LandseaException
     *
     */
    public abstract void submitCustom(ApprovalRecord insertApproval, ApprovalCheckResult checkResult)
        throws LandseaException;
    
    /**
     * 
     * [简要描述]：业务自定义处理</br>
     * [详细描述]：审核</br>
     * [作者]：Aaron(2017-10-16)</br>
     *
     * @param approvalReq
     * @param checkResult
     * @throws LandseaException
     *
     */
    public abstract void approvalCustom(ApprovalReq approvalReq, ApprovalCheckResult checkResult)
        throws LandseaException;
    
    /**
     * 
     * [简要描述]：检查是否有审核权限</br>
     * [详细描述]：</br>
     * [作者]：Aaron(2017-10-16)</br>
     *
     * @param currentApprovalRole 可审核的角色
     * @param approvalHelper 辅助类
     * @throws LandseaException 如果抛异常，则没有权限审核
     *
     */
    protected void checkCurrentApprovalAuth(String currentApprovalRole, ApprovalHelper approvalHelper)
        throws LandseaException
    {
        Integer userId = SecurityUtils.getCurrentLogin().getUserId();
        
        // 获取当前登陆者是否有审核角色
        List<UserRoleDTO> roleList = approvalHelper.getUserReadMapper().getUserRolesWithCodeByUserId(userId);
        if (CollectionUtils.isEmpty(roleList))
        {
            throw LandseaException.createException(ApprovalResultCode.E00650008);
        }
        
        boolean canApproval = false;
        for (UserRoleDTO userRole : roleList)
        {
            if (currentApprovalRole.equals(userRole.getCode()))
            {
                canApproval = true;
                break;
            }
        }
        
        if (!canApproval)
        {
            throw LandseaException.createException(ApprovalResultCode.E00650008);
        }
    }
}
